package worldinruin.controllers;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.util.LinkedList;
import java.util.List;

import javax.swing.AbstractAction;

import worldinruin.GameDataHandler;
import worldinruin.IGameDataHandler;
import worldinruin.core.IBuilding;
import worldinruin.core.IGame;
import worldinruin.core.IMap;
import worldinruin.core.IPlayer;
import worldinruin.core.IResourceBuilding;
import worldinruin.core.ISoldierBuilding;
import worldinruin.core.imp.Game;
import worldinruin.core.imp.Player;
import worldinruin.core.imp.Resources;
import worldinruin.core.imp.Troop;
import worldinruin.core.imp.buildings.BuildingTypes;
import worldinruin.core.imp.buildings.City;
import worldinruin.core.imp.soldiers.Archer;
import worldinruin.core.imp.soldiers.Catapult;
import worldinruin.core.imp.soldiers.Cavalier;
import worldinruin.core.imp.soldiers.Swordsman;
import worldinruin.gui.IGui;
import worldinruin.resources.Components;
import worldinruin.resources.Panels;

public class GameController extends AbstractAction {
	
	
	private IGameDataHandler dataHandler = GameDataHandler.getInstance();
	private IGui gui;
	private IGame game;
	
	/**
	 * Creates and sets a new game with the chosen amount of players on the chosen map.
	 * @param playerStrings List of players starting on the game board.
	 * @param map Chosen map.
	 */
	public void createNewGame(List<String> playerStrings, IMap map) {
		setGame(new Game(createPlayerList(playerStrings), map));
		startGame();
	}
	
	/**
	 * Sets game to gamecontroller.
	 * @param game Game to connect to gamecontroller.
	 */
	public void setGame(IGame game) {
		this.game = game;
	}
	
	/**
	 * Creates a list of player-objects
	 * @param playerStrings List of player-strings.
	 * @return List of player-objects.
	 */
	private List<IPlayer> createPlayerList(List<String> playerStrings) {
		List<IPlayer> playerList = new LinkedList<IPlayer>();
		Color[] playerColor = {Color.red, Color.blue, Color.green, Color.magenta};
		int i = 0;
		for(String playerName: playerStrings) {
			playerList.add(new Player(playerName, playerColor[i]));
			i++;
		}
		return playerList;
	}
	
	/**
	 * Starts the game by showing it in gameview.
	 * @param game
	 */
	public void startGame() {
		dataHandler.setGame(game);
		gui.addGameViewMainPanel(game);
		placeOutCitys();
		placeOutTroop();
		gui.showPage(Panels.GAMEVIEWMAINPANEL.toString());
	}
	
	/**
	 * Quits the current game and returns to mainmenu.
	 */
	public void quitGame() {
		game = null;
		gui.showPage(Panels.MAINMENUPANEL.toString());
	}
	
	/**
	 * Ends the active player's turn.
	 */
	public void endTurn() {
		gui.setActivePlayer();
		for(IBuilding building : game.getActivePlayer().getBuildings()) {
			if(building.getBuildingType() != BuildingTypes.CITY &&
					building.getBuildingType() != BuildingTypes.BARRACK) {
				game.getActivePlayer().addToResources(((IResourceBuilding)building).getPrice());
			}
		}
	}
	
	/**
	 * Places out troops on the gameboard for all the players in the game.
	 */
	public void placeOutTroop() {
		for(IPlayer p : game.getPlayers()) {
			Troop troop = new Troop(p, p.getBuildings().get(0).getTile());
			troop.add(new Swordsman(), 20);
			troop.add(new Archer(), 20);
			troop.add(new Cavalier(), 20);
			troop.add(new Catapult(), 20);
		}
	}
	
	/**
	 * Places out cities on the gameboard for all the players in the game.
	 */
	public void placeOutCitys() {
		int[] cityCoordinates = calculateCityCoordinates(game.getPlayers().size());
		int row = 0;
		int column = 1;
		for (IPlayer p : game.getPlayers()) {
			IBuilding city = new City(game.getMap().getTile(cityCoordinates[row], cityCoordinates[column]), p);
			p.addBuilding(city);
			game.getMap().getTile(cityCoordinates[row], cityCoordinates[column]).addBuilding(city);
			row += 2;
			column += 2;
		}
	}

	/**
	 * Calculates the starting position for the players.
	 * @param numberOfPlayers Number of players playing the game.
	 * @return An array of starting positions.
	 */
	public int[] calculateCityCoordinates(int numberOfPlayers) {
		int[] coordinates;
		int numberOfcolumns = game.getMap().getNumberOfColumns()-1;
		int numberOfRows = game.getMap().getNumberOfRows()-1;
		coordinates = new int[numberOfPlayers*2];
		coordinates[0] = 0;
		coordinates[1] = 0;
		coordinates[2] = numberOfRows;
		coordinates[3] = numberOfcolumns;
		if (numberOfPlayers >= 3 ) {
			coordinates[4] = numberOfRows;
			coordinates[5] = 0;
		}
		if (numberOfPlayers == 4) { 
			coordinates[6] = 0;
			coordinates[7] = numberOfcolumns;
		}
		return coordinates;
		
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		
		if (gui == null){
			gui = dataHandler.getGui();
		}
		
		Object o = e.getSource();
		
		if(o.equals(getValue(Components.startGameButton))) {
			createNewGame(gui.getPlayerNames(), gui.getChosenMap());
		}
		
		else if (o.equals(getValue(Components.backButton)) || o.equals(getValue(Components.quitGameMenuItem))){			
			quitGame();
		}
		
		else if (o.equals(getValue(Components.endTurnButton))) {
			endTurn();
			gui.updateMessage(game.getActivePlayer().getName() + "'s turn");
		}
		
	}
}
